File System Access APIã®å æ¬çã¬ã€ãããã©ãŠã¶ããããŒã«ã«ãã¡ã€ã«ã®å€æŽãçŽæ¥ç£èŠããæ¹æ³ããå®äŸããã¹ããã©ã¯ãã£ã¹ã亀ããŠè§£èª¬ããŠã§ãã¢ããªã®æªæ¥ãæ¢ããŸãã
ãªã¢ã«ã¿ã€ã ããã³ããšã³ãã®åãè§£æŸããïŒãã¡ã€ã«ã·ã¹ãã ãã£ã¬ã¯ããªç£èŠã®è©³çŽ°è§£èª¬
ããŒã«ã«ãã£ã¹ã¯äžã®ãããžã§ã¯ããã©ã«ãã«å ãã倿Žãå³åº§ã«åæ ããããŠã§ãããŒã¹ã®ã³ãŒããšãã£ã¿ãæ³åããŠã¿ãŠãã ãããã«ã¡ã©ããæ°ããç»åã远å ãããšèªåçã«æŽæ°ããããã©ãŠã¶ããŒã¹ã®ãã©ãã®ã£ã©ãªãŒãæãæµ®ãã¹ãŠãã ããããããã¯ãããŒã«ã«ã®ãã°ãã¡ã€ã«ãæŽæ°ãããã«ã€ããŠãªã¢ã«ã¿ã€ã ã§ãã£ãŒããåæç»ããããŒã¿å¯èŠåããŒã«ãèããŠã¿ãŠãã ãããäœå幎ãã®éããã®ãããªããŒã«ã«ãã¡ã€ã«ã·ã¹ãã ãšã®é«åºŠãªçµ±åã¯ããã€ãã£ããã¹ã¯ãããã¢ããªã±ãŒã·ã§ã³ã®ç¬å£å Žã§ããããã©ãŠã¶ã¯ãã»ãã¥ãªãã£äžã®çç±ããããµã³ãããã¯ã¹ãšããå®å šãªè·é¢ã«çœ®ãããŠããã®ã§ãã
仿¥ããã®ãã©ãã€ã ã¯åçã«å€åããŠããŸããææ°ã®ãã©ãŠã¶APIã®ãããã§ããŠã§ããšãã¹ã¯ãããã¢ããªã±ãŒã·ã§ã³ã®å¢çç·ã¯ææ§ã«ãªãã€ã€ãããŸãããã®æµãããªãŒãããæã匷åãªããŒã«ã®äžã€ãFile System Access APIã§ãããããã«ãããŠã§ãã¢ããªã±ãŒã·ã§ã³ã¯ãŠãŒã¶ãŒã®èš±å¯ã«åºã¥ããŠããŒã«ã«ã®ãã¡ã€ã«ããã£ã¬ã¯ããªã®èªã¿åããæžã蟌ã¿ããããŠä»åã®ããŒãã§æãéèŠãªç£èŠãè¡ãããšãã§ããŸãããã£ã¬ã¯ããªç£èŠãŸãã¯ãã¡ã€ã«å€æŽç£èŠãšããŠç¥ããããã®æ©èœã¯ããã¯ãã«ã§å¿çæ§ãé«ããé«åºŠã«çµ±åããããŠã§ãäœéšãåµé ããããã®æ°ããªããã³ãã£ã¢ãéããŸãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãããã³ããšã³ãã«ããããã¡ã€ã«ã·ã¹ãã ãã£ã¬ã¯ããªç£èŠã®äžçãæ·±ãæãäžããŠãããŸããåºç€ãšãªãAPIãæ¢æ±ããå ç¢ãªãŠã©ããã£ãŒïŒç£èŠããã°ã©ã ïŒããŒãããæ§ç¯ãããã¯ããã¯ãåæããå®éã®ãŠãŒã¹ã±ãŒã¹ãæ€èšããããã©ãŒãã³ã¹ãã»ãã¥ãªãã£ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãšããéèŠãªèª²é¡ãä¹ãè¶ããæ¹æ³ã解説ããŸããæ¬¡äžä»£ã®åªãããŠã§ãããŒã¹IDEãæ§ç¯ããŠããæ¹ã§ããã·ã³ãã«ãªãŠãŒãã£ãªãã£ããŒã«ãäœæããŠããæ¹ã§ãããã®æè¡ãçè§£ããããšã¯ãã¢ãã³ãªãŠã§ãã®ããã³ã·ã£ã«ãæå€§éã«åŒãåºãããã®éµãšãªããŸãã
é²åïŒåçŽãªãã¡ã€ã«å ¥åãããªã¢ã«ã¿ã€ã ç£èŠãž
File System Access APIã®éèŠæ§ãå®å šã«çè§£ããããã«ã¯ããŠã§ãã«ããããã¡ã€ã«ãã³ããªã³ã°ã®æ©ã¿ãæ¯ãè¿ãããšã圹ç«ã¡ãŸãã
åŸæ¥ã®ã¢ãããŒãïŒ<input type="file">
é·ãéããŠãŒã¶ãŒã®ãã¡ã€ã«ã·ã¹ãã ãžã®å¯äžã®ã²ãŒããŠã§ã€ã¯ãå°å³ãª<input type="file">èŠçŽ ã§ãããããã¯åçŽãªãã¡ã€ã«ã¢ããããŒãã®ããã®ä¿¡é Œã§ããäž»åããŒã«ã§ãããä»ããªãããã§ãããããããã®å¶éã¯å€§ããªãã®ã§ããïŒ
- ãŠãŒã¶ãŒäž»å°ãã€äžåéãïŒ ãŠãŒã¶ãŒã¯æ¯åæåã§ãã¿ã³ãã¯ãªãã¯ãããã¡ã€ã«ãéžæããå¿ èŠããããŸããæ°žç¶æ§ã¯ãããŸããã
- ãã¡ã€ã«ã®ã¿ïŒ 1ã€ãŸãã¯è€æ°ã®ãã¡ã€ã«ãéžæã§ããŸãããããã£ã¬ã¯ããªå šäœãéžæããããšã¯ã§ããŸããã§ããã
- ç£èŠæ©èœãªãïŒ ãã¡ã€ã«ãéžæããããšããã©ãŠã¶ã¯ãã£ã¹ã¯äžã®å ã®ãã¡ã€ã«ã«äœãèµ·ãã£ãããç¥ãè¡ããããŸããã§ãããããã倿Žããããåé€ããããããŠãããŠã§ãã¢ããªã¯é¢ç¥ããŸããã§ããã
äžæ©åé²ïŒãã©ãã°ïŒããããAPI
ãã©ãã°ïŒããããAPIã¯ããŠãŒã¶ãŒããã¡ã€ã«ããã©ã«ãããŠã§ãããŒãžã«çŽæ¥ãã©ãã°ã§ããããã«ããããšã§ãã¯ããã«æ¹åããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸããŸãããããã¯ããçŽæçã§ãã¹ã¯ãããã©ã€ã¯ãªæäœæã§ããããããããã¡ã€ã«å ¥åãšåãæ ¹æ¬çãªå¶éãå ±æããŠããŸãããããã¯äžåéãã®ã€ãã³ãã§ãããšããããšã§ããã¢ããªã±ãŒã·ã§ã³ã¯ããã®ç¹å®ã®ç¬éã«ãã©ãã°ãããã¢ã€ãã ã®ã¹ãããã·ã§ãããåãåãã ãã§ããœãŒã¹ãã£ã¬ã¯ããªãšã®ç¶ç¶çãªæ¥ç¶ã¯ãããŸããã§ããã
ã²ãŒã ãã§ã³ãžã£ãŒïŒFile System Access API
File System Access APIã¯ãæ ¹æ¬çãªé£èºãæå³ããŸããããã¯ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã«ãã€ãã£ãã¢ããªã±ãŒã·ã§ã³ã«å¹æµããæ©èœãæäŸããæ°žç¶çãã€åŒ·åãªæ¹æ³ã§ãŠãŒã¶ãŒã®ããŒã«ã«ãã¡ã€ã«ã·ã¹ãã ãšå¯Ÿè©±ã§ããããã«èšèšãããŸããããã®æ žãšãªãååã¯ãã»ãã¥ãªãã£ããŠãŒã¶ãŒã®åæããããŠæ©èœæ§ã«åºã¥ããŠããŸãïŒ
- ãŠãŒã¶ãŒäžå¿ã®ã»ãã¥ãªãã£ïŒ ã¢ã¯ã»ã¹ããµã€ã¬ã³ãã«èš±å¯ãããããšã¯æ±ºããŠãããŸããããŠãŒã¶ãŒã¯åžžã«ããã€ãã£ãã®ãã©ãŠã¶ãã€ã¢ãã°ãéããŠç¹å®ã®ãã¡ã€ã«ããã£ã¬ã¯ããªãžã®èš±å¯ãäžããããä¿ãããŸãã
- æ°žç¶çãªãã³ãã«ïŒ ã¢ããªã±ãŒã·ã§ã³ã¯ãäžåéãã®ããŒã¿ããããåãåã代ããã«ããã³ãã«ïŒFileSystemFileHandle ãŸã㯠FileSystemDirectoryHandleïŒãšåŒã°ããç¹å¥ãªãªããžã§ã¯ããååŸããŸãããã®ãã³ãã«ã¯ããã£ã¹ã¯äžã®å®éã®ãã¡ã€ã«ããã£ã¬ã¯ããªãžã®æ°žç¶çãªãã€ã³ã¿ãšããŠæ©èœããŸãã
- ãã£ã¬ã¯ããªã¬ãã«ã®ã¢ã¯ã»ã¹ïŒ ãããæ±ºå®çãªæ©èœã§ãããã®APIã«ããããŠãŒã¶ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã«å¯Ÿãããã¹ãŠã®ãµããã£ã¬ã¯ããªãšãã¡ã€ã«ãå«ããã£ã¬ã¯ããªå šäœãžã®ã¢ã¯ã»ã¹ãèš±å¯ã§ããŸãã
ããã³ããšã³ãã§ãªã¢ã«ã¿ã€ã ã®ãã¡ã€ã«ç£èŠãå¯èœã«ããã®ã¯ããã®æ°žç¶çãªãã£ã¬ã¯ããªãã³ãã«ãªã®ã§ãã
File System Access APIãçè§£ããïŒã³ã¢ãã¯ãããžãŒ
ãã£ã¬ã¯ããªãŠã©ããã£ãŒãæ§ç¯ããåã«ããããæ©èœãããAPIã®äž»èŠã³ã³ããŒãã³ããçè§£ããå¿ èŠããããŸããAPIå šäœã¯éåæã§ããããã¡ã€ã«ã·ã¹ãã ãšå¯Ÿè©±ãããã¹ãŠã®æäœã¯Promiseãè¿ãããšãæå³ããããã«ãããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ã®å¿çæ§ãç¶æãããŸãã
ã»ãã¥ãªãã£ãšæš©éïŒãŠãŒã¶ãŒãå¶åŸ¡ãã
ãã®APIã®æãéèŠãªåŽé¢ã¯ããã®ã»ãã¥ãªãã£ã¢ãã«ã§ãããŠã§ããµã€ããåæã«ããªãã®ããŒããã©ã€ããã¹ãã£ã³ããããšã¯ã§ããŸãããã¢ã¯ã»ã¹ã¯å³å¯ã«ãªããã€ã³æ¹åŒã§ãã
- ååã¢ã¯ã»ã¹ïŒ ãŠãŒã¶ãŒã¯ãã¿ã³ã®ã¯ãªãã¯ãªã©ã®ã¢ã¯ã·ã§ã³ãããªã¬ãŒããããã«ãã£ãŠwindow.showDirectoryPicker()ã®ãããªAPIã¡ãœãããåŒã³åºãããå¿ èŠããããŸããããã«ãããããªãã¿ã®OSã¬ãã«ã®ãã€ã¢ãã°ããã¯ã¹ãéãããŠãŒã¶ãŒã¯ãã£ã¬ã¯ããªãéžæããŠæç€ºçã«ãã¢ã¯ã»ã¹ãèš±å¯ããªã©ã®ãã¿ã³ãã¯ãªãã¯ããŸãã
- æš©éã®ç¶æ ïŒ ç¹å®ã®ãã³ãã«ã«å¯Ÿãããµã€ãã®æš©éã¯ã'prompt'ïŒããã©ã«ãããŠãŒã¶ãŒã«å°ããå¿ èŠãããïŒã'granted'ïŒãµã€ããã¢ã¯ã»ã¹æš©ãæã€ïŒã'denied'ïŒãµã€ãã¯ã¢ã¯ã»ã¹ã§ãããåãã»ãã·ã§ã³ã§åèŠæ±ãã§ããªãïŒã®3ã€ã®ç¶æ ã®ããããã«ãªããŸãã
- æ°žç¶æ§ïŒ ããè¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®ããã«ããã©ãŠã¶ã¯ã€ã³ã¹ããŒã«æžã¿ã®PWAããšã³ã²ãŒãžã¡ã³ãã®é«ããµã€ãã«å¯ŸããŠãã»ãã·ã§ã³ãè¶ããŠ'granted'ã®æš©éãæ°žç¶åããããšããããŸããããã«ããããŠãŒã¶ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã蚪ãããã³ã«ãããžã§ã¯ããã©ã«ããåéžæããå¿ èŠããªããªããããããŸãããçŸåšã®æš©éã®ç¶æ ã¯directoryHandle.queryPermission()ã§ç¢ºèªã§ããdirectoryHandle.requestPermission()ã§ææ Œããªã¯ãšã¹ãã§ããŸãã
ã¢ã¯ã»ã¹ãååŸããããã®äž»èŠã¡ãœãã
APIãžã®ãšã³ããªãã€ã³ãã¯ãwindowãªããžã§ã¯ãäžã®3ã€ã®ã°ããŒãã«ã¡ãœããã§ãïŒ
- window.showOpenFilePicker(): ãŠãŒã¶ãŒã«1ã€ãŸãã¯è€æ°ã®ãã¡ã€ã«ãéžæããããä¿ããŸããFileSystemFileHandleãªããžã§ã¯ãã®é åãè¿ããŸãã
- window.showDirectoryPicker(): ãããç§ãã¡ã®äž»èŠãªããŒã«ã§ãããŠãŒã¶ãŒã«ãã£ã¬ã¯ããªãéžæããããä¿ããŸããåäžã®FileSystemDirectoryHandleãè¿ããŸãã
- window.showSaveFilePicker(): ãŠãŒã¶ãŒã«ãã¡ã€ã«ãä¿åããå Žæãéžæããããä¿ããŸããæžã蟌ã¿çšã®FileSystemFileHandleãè¿ããŸãã
ãã³ãã«ã®åïŒFileSystemDirectoryHandle
FileSystemDirectoryHandleãååŸãããšããã®ãã£ã¬ã¯ããªã衚ã匷åãªãªããžã§ã¯ããæã«å ¥ããããšã«ãªããŸããããã«ã¯ãã£ã¬ã¯ããªã®ã³ã³ãã³ãã¯å«ãŸããŠããŸããããããããšå¯Ÿè©±ããããã®ã¡ãœãããæäŸãããŠããŸãïŒ
- å埩åŠçïŒ éåæã€ãã¬ãŒã¿ã䜿çšããŠãã£ã¬ã¯ããªã®ã³ã³ãã³ããå埩åŠçã§ããŸãïŒfor await (const entry of directoryHandle.values()) { ... }ãåentryã¯FileSystemFileHandleãŸãã¯å¥ã®FileSystemDirectoryHandleã«ãªããŸãã
- ç¹å®ã®ãšã³ããªã®è§£æ±ºïŒ directoryHandle.getFileHandle('filename.txt')ãdirectoryHandle.getDirectoryHandle('subfolder')ã䜿çšããŠãç¹å®ã®æ¢ç¥ã®ãã¡ã€ã«ããµããã£ã¬ã¯ããªã®ãã³ãã«ãååŸã§ããŸãã
- 倿ŽïŒ äžèšã®ã¡ãœããã«{ create: true }ãªãã·ã§ã³ã远å ããããšã§æ°ãããã¡ã€ã«ããµããã£ã¬ã¯ããªãäœæããããdirectoryHandle.removeEntry('item-to-delete')ã§ããããåé€ãããã§ããŸãã
åé¡ã®æ žå¿ïŒãã£ã¬ã¯ããªç£èŠã®å®è£
ããã«éèŠãªè©³çްããããŸãïŒFile System Access APIã¯ãNode.jsã®fs.watch()ã®ãããªãã€ãã£ãã®ã€ãã³ãããŒã¹ã®ç£èŠã¡ã«ããºã ãæäŸããŸãããdirectoryHandle.on('change', ...)ã®ãããªã¡ãœããã¯ååšããŸãããããã¯é »ç¹ã«ãªã¯ãšã¹ããããæ©èœã§ãããä»ã®ãšãããç£èŠããžãã¯ã¯èªåãã¡ã§å®è£ ããå¿ èŠããããŸãã
æãäžè¬çã§å®çšçãªã¢ãããŒãã¯å®æçããŒãªã³ã°ã§ããããã¯ãäžå®ééã§ãã£ã¬ã¯ããªã®ç¶æ ã®ãã¹ãããã·ã§ããããååŸãããããåã®ã¹ãããã·ã§ãããšæ¯èŒããŠå€æŽãæ€åºãããã®ã§ãã
åçŽãªã¢ãããŒãïŒã·ã³ãã«ãªããŒãªã³ã°ã«ãŒã
åºæ¬çãªå®è£ ã¯æ¬¡ã®ããã«ãªããŸãïŒ
// ã³ã³ã»ããã説æããããã®ç°¡ç¥åãããäŸ
let initialFiles = new Set();
async function watchDirectory(directoryHandle) {
const currentFiles = new Set();
for await (const entry of directoryHandle.values()) {
currentFiles.add(entry.name);
}
// 以åã®ç¶æ ãšæ¯èŒããïŒãã®ããžãã¯ã¯åçŽãããŸãïŒ
console.log("ãã£ã¬ã¯ããªããã§ãã¯ããŸãããçŸåšã®ãã¡ã€ã«:", Array.from(currentFiles));
// 次ã®ãã§ãã¯ã®ããã«ç¶æ ãæŽæ°
initialFiles = currentFiles;
}
// ç£èŠãéå§
async function start() {
const directoryHandle = await window.showDirectoryPicker();
setInterval(() => watchDirectory(directoryHandle), 2000); // 2ç§ããšã«ãã§ãã¯
}
ããã¯æ©èœããŸãããéåžžã«éå®çã§ãããããã¬ãã«ã®ãã£ã¬ã¯ããªãããã§ãã¯ããã远å /åé€ããæ€åºã§ããïŒå€æŽã¯æ€åºäžå¯ïŒãã«ãã»ã«åãããŠããŸãããåºçºç¹ã§ã¯ãããŸããããã£ãšè¯ãæ¹æ³ããããŸãã
ããæŽç·Žãããã¢ãããŒãïŒååž°çãªãŠã©ããã£ãŒã¯ã©ã¹ã®æ§ç¯
æ¬åœã«åœ¹ç«ã€ãã£ã¬ã¯ããªãŠã©ããã£ãŒãäœæããã«ã¯ãããå ç¢ãªãœãªã¥ãŒã·ã§ã³ãå¿ èŠã§ãããã£ã¬ã¯ããªãååž°çã«ã¹ãã£ã³ãããã¡ã€ã«ã®ã¡ã¿ããŒã¿ã远跡ããŠå€æŽãæ€åºããããŸããŸãªçš®é¡ã®å€æŽã«å¯ŸããŠæç¢ºãªã€ãã³ããçºè¡ããã¯ã©ã¹ãèšèšããŸãããã
ã¹ããã1ïŒè©³çްãªã¹ãããã·ã§ããã®ååŸ
ãŸãããã£ã¬ã¯ããªãååž°çã«èµ°æ»ãããã®å 容ã®è©³çްãªããããæ§ç¯ã§ãã颿°ãå¿ èŠã§ãããã®ãããã«ã¯ããã¡ã€ã«åã ãã§ãªãã倿޿€åºã«äžå¯æ¬ ãªlastModifiedã¿ã€ã ã¹ã¿ã³ãã®ãããªã¡ã¿ããŒã¿ãå«ããã¹ãã§ãã
// ãã£ã¬ã¯ããªã®ã¹ãããã·ã§ãããååž°çã«äœæãã颿°
async function createSnapshot(dirHandle, path = '') {
const snapshot = new Map();
for await (const entry of dirHandle.values()) {
const currentPath = path ? `${path}/${entry.name}` : entry.name;
if (entry.kind === 'file') {
const file = await entry.getFile();
snapshot.set(currentPath, {
lastModified: file.lastModified,
size: file.size,
handle: entry
});
} else if (entry.kind === 'directory') {
const subSnapshot = await createSnapshot(entry, currentPath);
subSnapshot.forEach((value, key) => snapshot.set(key, value));
}
}
return snapshot;
}
ã¹ããã2ïŒã¹ãããã·ã§ãããæ¯èŒããŠå€æŽãæ€åºãã
次ã«ãå€ãã¹ãããã·ã§ãããšæ°ããã¹ãããã·ã§ãããæ¯èŒããäœã倿Žãããããæ£ç¢ºã«ç¹å®ãã颿°ãå¿ èŠã§ãã
// 2ã€ã®ã¹ãããã·ã§ãããæ¯èŒãã倿Žç¹ãè¿ã颿°
function compareSnapshots(oldSnapshot, newSnapshot) {
const changes = {
added: [],
modified: [],
deleted: []
};
// 远å ã»å€æŽããããã¡ã€ã«ã®ãã§ãã¯
newSnapshot.forEach((newFile, path) => {
const oldFile = oldSnapshot.get(path);
if (!oldFile) {
changes.added.push({ path, handle: newFile.handle });
} else if (oldFile.lastModified !== newFile.lastModified || oldFile.size !== newFile.size) {
changes.modified.push({ path, handle: newFile.handle });
}
});
// åé€ããããã¡ã€ã«ã®ãã§ãã¯
oldSnapshot.forEach((oldFile, path) => {
if (!newSnapshot.has(path)) {
changes.deleted.push({ path });
}
});
return changes;
}
ã¹ããã3ïŒããžãã¯ãDirectoryWatcherã¯ã©ã¹ã«ã«ãã»ã«åãã
æåŸã«ããã¹ãŠãã¯ãªãŒã³ã§åå©çšå¯èœãªã¯ã©ã¹ã«ã©ããããŸãããã®ã¯ã©ã¹ã¯ç¶æ ãšããŒãªã³ã°ééã管çããã·ã³ãã«ãªã³ãŒã«ããã¯ããŒã¹ã®APIãæäŸããŸãã
class DirectoryWatcher {
constructor(directoryHandle, interval = 1000) {
this.directoryHandle = directoryHandle;
this.interval = interval;
this.lastSnapshot = new Map();
this.intervalId = null;
this.onChange = () => {}; // ããã©ã«ãã®ç©ºã®ã³ãŒã«ããã¯
}
async check() {
try {
const newSnapshot = await createSnapshot(this.directoryHandle);
const changes = compareSnapshots(this.lastSnapshot, newSnapshot);
if (changes.added.length > 0 || changes.modified.length > 0 || changes.deleted.length > 0) {
this.onChange(changes);
}
this.lastSnapshot = newSnapshot;
} catch (error) {
console.error("ãã¡ã€ã«å€æŽã®ãã§ãã¯äžã«ãšã©ãŒãçºçããŸãã:", error);
// ãã£ã¬ã¯ããªã«ã¢ã¯ã»ã¹ã§ããªããªã£ãå Žåã¯ãç£èŠã忢ããå¯èœæ§ããããŸã
this.stop();
}
}
async start(callback) {
if (this.intervalId) {
console.log("ãŠã©ããã£ãŒã¯ãã§ã«å®è¡äžã§ãã");
return;
}
this.onChange = callback;
// ããã«ååãã§ãã¯ãå®è¡
this.lastSnapshot = await createSnapshot(this.directoryHandle);
this.intervalId = setInterval(() => this.check(), this.interval);
console.log(`ã${this.directoryHandle.name}ãã®å€æŽç£èŠãéå§ããŸããã`);
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log(`ã${this.directoryHandle.name}ãã®ç£èŠã忢ããŸããã`);
}
}
}
// DirectoryWatcherã¯ã©ã¹ã®äœ¿ãæ¹
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
let watcher;
startButton.addEventListener('click', async () => {
try {
const directoryHandle = await window.showDirectoryPicker();
watcher = new DirectoryWatcher(directoryHandle, 2000); // 2ç§ããšã«ãã§ãã¯
watcher.start((changes) => {
console.log("倿Žãæ€åºãããŸãã:", changes);
// ããã§ããããã®å€æŽã«åºã¥ããŠUIãæŽæ°ã§ããŸã
});
} catch (error) {
console.error("ãŠãŒã¶ãŒããã€ã¢ãã°ããã£ã³ã»ã«ãããããšã©ãŒãçºçããŸããã", error);
}
});
stopButton.addEventListener('click', () => {
if (watcher) {
watcher.stop();
}
});
å®è·µçãªãŠãŒã¹ã±ãŒã¹ãšã°ããŒãã«ãªäŸ
ãã®æè¡ã¯åãªãçè«çãªæŒç¿ã§ã¯ãããŸãããäžçäžã®ãªãŒãã£ãšã³ã¹ãã¢ã¯ã»ã¹ã§ããã匷åã§å®çšçãªã¢ããªã±ãŒã·ã§ã³ãå¯èœã«ããŸãã
1. ãŠã§ãããŒã¹ã®IDEãšã³ãŒããšãã£ã¿
ããã¯å žåçãªãŠãŒã¹ã±ãŒã¹ã§ããVS Code for the WebãGitHub Codespacesã®ãããªããŒã«ã¯ãéçºè ãããŒã«ã«ã®ãããžã§ã¯ããã©ã«ããéãããšãå¯èœã«ããŸãããã£ã¬ã¯ããªãŠã©ããã£ãŒã¯ã次ã®ãããªå€æŽãç£èŠã§ããŸãïŒ
- ãã¡ã€ã«ããªãŒã®åæïŒ ãã£ã¹ã¯äžã§ïŒããããå¥ã®ã¢ããªã±ãŒã·ã§ã³ã䜿çšããŠïŒãã¡ã€ã«ãäœæãåé€ããŸãã¯åå倿Žããããšããšãã£ã¿ã®ãã¡ã€ã«ããªãŒãå³åº§ã«æŽæ°ãããŸãã
- ã©ã€ããªããŒã/ãã¬ãã¥ãŒïŒ ãŠã§ãéçºã«ãããŠãHTMLãCSSããŸãã¯JavaScriptãã¡ã€ã«ãžã®å€æŽãä¿åãããšããšãã£ã¿å ã®ãã¬ãã¥ãŒãã€ã³ãèªåçã«ãªãã¬ãã·ã¥ãããããã«ã§ããŸãã
- ããã¯ã°ã©ãŠã³ãã¿ã¹ã¯ïŒ ãã¡ã€ã«ãžã®å€æŽããããã¯ã°ã©ãŠã³ãã§ã®ãªã³ãã£ã³ã°ãåãã§ãã¯ããŸãã¯ã³ã³ãã€ã«ãããªã¬ãŒããããšããããŸãã
2. ã¯ãªãšã€ãã£ããããã§ãã·ã§ãã«åãããžã¿ã«è³ç£ç®¡çïŒDAMïŒ
äžçäžã®ã©ãã«ããŠããåçå®¶ãã«ã¡ã©ãã³ã³ãã¥ãŒã¿ã«æ¥ç¶ãããšãåçã¯ç¹å®ã®ãåä¿¡ããã©ã«ãã«ä¿åãããŸãããã®ãã©ã«ããžã®ã¢ã¯ã»ã¹ãèš±å¯ããããŠã§ãããŒã¹ã®åç管çããŒã«ã¯ãæ°ãã远å ããªããç£èŠã§ããŸããæ°ããJPEGãRAWãã¡ã€ã«ãçŸãããšããã«ããŠã§ãã¢ããªã¯ãããèªåçã«ã€ã³ããŒããããµã ãã€ã«ãçæããæåã®ä»å ¥ãªãã«ãŠãŒã¶ãŒã®ã©ã€ãã©ãªã«è¿œå ã§ããŸãã
3. ç§åŠããã³ããŒã¿åæããŒã«
ç ç©¶å®€ã®æ©åšããæå®ãããåºåãã£ã¬ã¯ããªã«1æéãããæ°çŸã®å°ããªCSVãJSONããŒã¿ãã¡ã€ã«ãçæãããããããŸããããŠã§ãããŒã¹ã®ããã·ã¥ããŒãããã®ãã£ã¬ã¯ããªãç£èŠããŸããæ°ããããŒã¿ãã¡ã€ã«ã远å ããããšãããããè§£æããã°ã©ãããã£ãŒããçµ±èšãµããªãŒããªã¢ã«ã¿ã€ã ã§æŽæ°ããé²è¡äžã®å®éšã«é¢ãã峿ã®ãã£ãŒãããã¯ãæäŸããŸããããã¯çç©åŠããéèãŸã§ãäžçäžã®åéã§é©çšå¯èœã§ãã
4. ããŒã«ã«ãã¡ãŒã¹ãã®ã¡ã¢åãããã³ããã¥ã¡ã³ããŒã·ã§ã³ã¢ããª
å€ãã®ãŠãŒã¶ãŒã¯ãã¡ã¢ããã¬ãŒã³ããã¹ããMarkdownãã¡ã€ã«ãšããŠããŒã«ã«ãã©ã«ãã«ä¿åããããšã奜ã¿ãŸããããã«ãããObsidianãTyporaã®ãããªåŒ·åãªãã¹ã¯ããããšãã£ã¿ã䜿çšã§ããŸããããã°ã¬ãã·ããŠã§ãã¢ããªïŒPWAïŒã¯ããã®ãã©ã«ããç£èŠããã³ã³ãããªã³ãšããŠæ©èœã§ããŸãããŠãŒã¶ãŒããã¡ã€ã«ãç·šéããŠä¿åãããšããŠã§ãã¢ããªã¯å€æŽãæ€åºããèªèº«ã®ãã¥ãŒãæŽæ°ããŸããããã«ããããŠãŒã¶ãŒã®ããŒã¿æææš©ãå°éãã€ã€ããã€ãã£ãããŒã«ãšãŠã§ãããŒã«éã®ã·ãŒã ã¬ã¹ã§åæãããäœéšãçãŸããŸãã
課é¡ãå¶éãããã³ãã¹ããã©ã¯ãã£ã¹
éåžžã«åŒ·åã§ããäžæ¹ããã£ã¬ã¯ããªç£èŠã®å®è£ ã«ã¯äžé£ã®èª²é¡ãšè²¬ä»»ã䌎ããŸãã
ãã©ãŠã¶ã®äºææ§
File System Access APIã¯ææ°ã®æè¡ã§ãã2023幎åŸåçŸåšãäž»ã«Google ChromeãMicrosoft EdgeãOperaãªã©ã®ChromiumããŒã¹ã®ãã©ãŠã¶ã§ãµããŒããããŠããŸããFirefoxãSafariã§ã¯å©çšã§ããŸããããããã£ãŠã以äžã®ããšãéèŠã§ãïŒ
- æ©èœæ€åºïŒ APIã䜿çšããããšããåã«ãåžžã«'showDirectoryPicker' in windowã®ååšã確èªããŠãã ããã
- ãã©ãŒã«ããã¯ã®æäŸïŒ APIããµããŒããããŠããªãå Žåã¯ããšã¯ã¹ããªãšã³ã¹ãé©åã«ããŠã³ã°ã¬ãŒãããŸããåŸæ¥ã®<input type="file" multiple>èŠçŽ ã«ãã©ãŒã«ããã¯ãããµããŒããããŠãããã©ãŠã¶ã§å©çšå¯èœãªæ¡åŒµæ©èœã«ã€ããŠãŠãŒã¶ãŒã«ç¥ãããããšãã§ããŸãã
ããã©ãŒãã³ã¹ã«é¢ããèæ ®äºé
ããŒãªã³ã°ã¯ãã·ã¹ãã ã¬ãã«ã®ã€ãã³ãããŒã¹ã®ã¢ãããŒããããæ¬è³ªçã«å¹çãå£ããŸããããã©ãŒãã³ã¹ã³ã¹ãã¯ãç£èŠå¯Ÿè±¡ã®ãã£ã¬ã¯ããªã®ãµã€ãºãšæ·±ããããã³ããŒãªã³ã°ééã®é »åºŠã«çŽæ¥é¢ä¿ããŸãã
- å€§èŠæš¡ãªãã£ã¬ã¯ããªïŒ æ°äžã®ãã¡ã€ã«ãæã€ãã£ã¬ã¯ããªãæ¯ç§ã¹ãã£ã³ãããšãããªãã®CPUãªãœãŒã¹ãæ¶è²»ããã©ãããããã®ããããªãŒãæ¶èãããå¯èœæ§ããããŸãã
- ããŒãªã³ã°é »åºŠïŒ ãŠãŒã¹ã±ãŒã¹ã«ãšã£ãŠèš±å®¹ã§ããæãé·ãééãéžæããŠãã ããããªã¢ã«ã¿ã€ã ã®ã³ãŒããšãã£ã¿ã¯1ã2ç§ã®ééãå¿ èŠãããããŸããããåçã©ã€ãã©ãªã®ã€ã³ããŒã¿ãŒã¯10ã15ç§ã®ééã§ååãããããŸããã
- æé©åïŒ ç§ãã¡ã®ã¹ãããã·ã§ããæ¯èŒã¯ããã¡ã€ã«ã®å 容ãããã·ã¥åãããããã¯ããã«é«éãªlastModifiedãšsizeã®ã¿ããã§ãã¯ããããšã§ããã§ã«æé©åãããŠããŸãã絶察ã«å¿ èŠãªå Žåãé€ããããŒãªã³ã°ã«ãŒãå ã§ãã¡ã€ã«ã®å 容ãèªã¿åãããšã¯é¿ããŠãã ããã
- ãã©ãŒã«ã¹ã®å€æŽïŒ è³¢ãæé©åãšããŠãPage Visibility APIã䜿çšããŠãã©ãŠã¶ã®ã¿ãããã©ãŒã«ã¹ãããŠããªããšãã«ãŠã©ããã£ãŒãäžæåæ¢ããæ¹æ³ããããŸãã
ã»ãã¥ãªãã£ãšãŠãŒã¶ãŒã®ä¿¡é Œ
ä¿¡é ŒãæãéèŠã§ãããŠãŒã¶ãŒããŠã§ããµã€ãã«ããŒã«ã«ãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ãèš±å¯ããããšã«æ éã«ãªãã®ã¯åœç¶ã§ããéçºè ãšããŠãããªãã¯ãã®åã責任ãæã£ãŠç®¡çããªããã°ãªããŸããã
- éææ§ãä¿ã€ïŒ UIã§ãã£ã¬ã¯ããªãžã®ã¢ã¯ã»ã¹ããªãå¿ èŠãªã®ããæç¢ºã«èª¬æããŠãã ããããã©ã€ããã¡ã€ã«åæãæå¹ã«ããã«ã¯ããããžã§ã¯ããã©ã«ããéžæããŠãã ãããã®ãããªã¡ãã»ãŒãžã¯ãäžè¬çãªããã©ã«ããéãããã¿ã³ãããã¯ããã«åªããŠããŸãã
- ãŠãŒã¶ãŒã¢ã¯ã·ã§ã³æã«ã¢ã¯ã»ã¹ãèŠæ±ããïŒ ãã¿ã³ã®ã¯ãªãã¯ãªã©ãçŽæ¥çã§æçœãªãŠãŒã¶ãŒã¢ã¯ã·ã§ã³ãªãã«showDirectoryPicker()ããã³ãããããªã¬ãŒããªãã§ãã ããã
- æåŠãé©åã«åŠçããïŒ ãŠãŒã¶ãŒãããã£ã³ã»ã«ããã¯ãªãã¯ããããæš©éèŠæ±ãæåŠããå Žåãã¢ããªã±ãŒã·ã§ã³ã¯å£ããããšãªããã®ç¶æ ããšã¬ã¬ã³ãã«åŠçããå¿ èŠããããŸãã
UI/UXã®ãã¹ããã©ã¯ãã£ã¹
åªãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã¯ããã®åŒ·åãªæ©èœãçŽæçã§å®å šã«æããããããã®éµã§ãã
- æç¢ºãªãã£ãŒãããã¯ãæäŸããïŒ çŸåšç£èŠäžã®ãã£ã¬ã¯ããªã®ååãåžžã«è¡šç€ºããŠãã ãããããã«ããããŠãŒã¶ãŒã¯ã©ã®ã¢ã¯ã»ã¹ãèš±å¯ãããããæãåºãããšãã§ããŸãã
- æç¢ºãªã³ã³ãããŒã«ãæäŸããïŒ æç¢ºãªãç£èŠéå§ãããã³ãç£èŠåæ¢ããã¿ã³ãå«ããŠãã ããããŠãŒã¶ãŒã¯åžžã«ããã»ã¹ãå¶åŸ¡ã§ããŠãããšæããã¹ãã§ãã
- ãšã©ãŒãåŠçããïŒ ã¢ããªã®å®è¡äžã«ãŠãŒã¶ãŒãç£èŠå¯Ÿè±¡ã®ãã©ã«ãã®ååã倿Žãããåé€ãããããå Žåã¯ã©ããªããŸããïŒæ¬¡ã®ããŒãªã³ã°ã§ãããããšã©ãŒãã¹ããŒãããŸãããããã®ãšã©ãŒããã£ããããŠãŠãŒã¶ãŒã«éç¥ããå Žåã«ãã£ãŠã¯ãŠã©ããã£ãŒã忢ããŠæ°ãããã£ã¬ã¯ããªãéžæããããã«ä¿ããŸãã
æªæ¥ïŒãŠã§ãã«ããããã¡ã€ã«ã·ã¹ãã ã¢ã¯ã»ã¹ã®æ¬¡ãªãå±éã¯ïŒ
çŸåšã®ããŒãªã³ã°ããŒã¹ã®ã¢ãããŒãã¯è³¢æã§å¹æçãªåé¿çã§ãããçæ³çãªé·æçãªè§£æ±ºçã§ã¯ãããŸããããŠã§ãæšæºã³ãã¥ããã£ã¯ãã®ããšãããèªèããŠããŸãã
æãæåŸ ãããå°æ¥ã®éçºã¯ããã€ãã£ãã®ã€ãã³ãé§ååãã¡ã€ã«ã·ã¹ãã ç£èŠã¡ã«ããºã ãAPIã«è¿œå ãããå¯èœæ§ã§ããããã¯çã®ã²ãŒã ãã§ã³ãžã£ãŒãšãªãããã©ãŠã¶ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã èªèº«ã®å¹ççãªéç¥ã·ã¹ãã ïŒLinuxã®inotifyãmacOSã®FSEventsãWindowsã®ReadDirectoryChangesWãªã©ïŒã«ããã¯ã§ããããã«ãªããŸããããã«ãããããŒãªã³ã°ã®å¿ èŠããªããªããç¹ã«å€§èŠæš¡ãªãã£ã¬ã¯ããªãããããªãŒé§åã®ããã€ã¹ã§ã®ããã©ãŒãã³ã¹ãšå¹çãåçã«åäžããŸãã
ãã®ãããªæ©èœã®æç¢ºãªã¿ã€ã ã©ã€ã³ã¯ãããŸãããããã®å¯èœæ§ã¯ãŠã§ããã©ãããã©ãŒã ãé²ãæ¹åãæç¢ºã«ç€ºããŠããŸããããã¯ããŠã§ãã¢ããªã±ãŒã·ã§ã³ã®èœåããã©ãŠã¶ã®ãµã³ãããã¯ã¹ã«ãã£ãŠã§ã¯ãªããç§ãã¡ã®æ³ååã«ãã£ãŠã®ã¿å¶éãããæªæ¥ã§ãã
çµè«
File System Access APIã«ãã£ãŠå®çŸãããããã³ããšã³ãã®ãã¡ã€ã«ã·ã¹ãã ãã£ã¬ã¯ããªç£èŠã¯ã驿°çãªãã¯ãããžãŒã§ããããã¯ããŠã§ããšããŒã«ã«ã®ãã¹ã¯ãããç°å¢ãšã®éã«é·å¹Žååšããéå£ãåãæããæŽç·Žãããã€ã³ã¿ã©ã¯ãã£ãã§ãçç£æ§ã®é«ãæ°äžä»£ã®ãã©ãŠã¶ããŒã¹ã®ã¢ããªã±ãŒã·ã§ã³ãå¯èœã«ããŸããã³ã¢APIãçè§£ããå ç¢ãªããŒãªã³ã°æŠç¥ãå®è£ ããããã©ãŒãã³ã¹ãšãŠãŒã¶ãŒã®ä¿¡é Œã«é¢ãããã¹ããã©ã¯ãã£ã¹ãéµå®ããããšã§ãéçºè ã¯ãããŸã§ä»¥äžã«çµ±åããã匷åã«æããããäœéšãæ§ç¯ã§ããŸãã
çŸåšã¯ç¬èªã®ãŠã©ããã£ãŒãæ§ç¯ããããšã«é Œã£ãŠããŸãããããã§è°è«ããååã¯åºæ¬çãªãã®ã§ãããŠã§ããã©ãããã©ãŒã ãé²åãç¶ããäžã§ããŠãŒã¶ãŒã®ããŒã«ã«ããŒã¿ãšã·ãŒã ã¬ã¹ãã€å¹ççã«å¯Ÿè©±ããèœåã¯ãçŸä»£ã®ã¢ããªã±ãŒã·ã§ã³éçºã®ç€ã§ããç¶ããéçºè ããã©ãŠã¶ããããã°èª°ã§ãã¢ã¯ã»ã¹ã§ããçã«ã°ããŒãã«ãªããŒã«ãæ§ç¯ããããšãå¯èœã«ããŸãã